package rpcx_media_server

import (
	"errors"
	"fmt"
	"time"

	"gobase/rpcx_work_flow"

	"github.com/smallnest/rpcx/server"
)

type ProtocolOption struct {
	/**是否开启转换为hls*/
	Enable_hls bool
	/**是否开启MP4录制*/
	Enable_mp4 bool
	/**是否开启转换为rtsp/webrtc*/
	Enable_rtsp bool
	/**是否开启转换为rtmp/flv*/
	Enable_rtmp bool
	/**是否开启转换为http-ts/ws-ts*/
	Enable_ts bool
	/**是否开启转换为http-fmp4/ws-fmp4*/
	Enable_fmp4 bool

	/**转协议是否开启音频*/
	Enable_audio bool
	/**添加静音音频,在关闭音频时,此开关无效*/
	Add_mute_audio bool
}

type AddStreamProxyParam struct {
	/*结构化中心的目标流的app*/
	DestApp string
	/*结构化中心的目标流的stream*/
	DestStream string
	/*媒体中心的IP地址*/
	SourceIP string
	/*媒体中心的端口*/
	SourcePort int32
	/*媒体中心的源流的app*/
	SourceApp string
	/*媒体中心的源流的stream*/
	SourceStream   string
	Retry_count    int32
	ProtocolOption ProtocolOption
	Tid            string
}

//换到 gobase/http/dm_type.go
/*通用答复*/
type CommonResponse struct {
	Code int32
	Msg  string
}

// enum EnumSnapshotJobStatus {
// Unknown := 0
// WaitingToSnapshot := 1
// WaitingToDownload := 2
// WaitingToSend := 3
// SendSuccess := 4
// SendFailedWithoutRetry := 5
// WaitingToSendAgain := 6
// }

type DelStreamProxyParam struct {
	Key string
	Tid string
}

type GetStreamStatusRequest struct {
	Tid    string
	App    string
	Stream string
}

type StreamStatResponse struct {
	Code             int32
	Msg              string
	TotalReaderCount int32
	App              string
	Stream           string
}

type AllStreamStatResponse struct {
	Code    int32
	Msg     string
	AllStat []StreamStatResponse
}

type OpenRtpServerRequest struct {
	Port       int32
	StreamType int32
	StreamId   string
	EnableTcp  bool
	Tid        string
}

type OpenRtpServerForHistoryRequest struct {
	Port        int32
	StreamType  int32
	DeviceId    string
	StartTime   string
	EndTime     string
	PlayTime    string
	IsFirstPlay bool
	Tid         string
}

type GetM3u8UrlRequest struct {
	EeviceId  string
	StartTime string
	EndTime   string
	PlayTime  string
	Tid       string
}

type GetM3u8UrlResponse struct {
	Code    int32
	Msg     string
	M3u8Url string
}

type OpenRtpServerResponse struct {
	Code      int32
	Msg       string
	Port      int32
	StreamId  string
	EnableTcp bool
}

type MergeStreamRect struct {
	X       int32
	Y       int32
	Width   int32
	Height  int32
	PlayUrl string
}

type StartMergeStreamRequest struct {
	Tid            string
	Width          int32
	Height         int32
	ChildRect      []MergeStreamRect
	Ssrc           int32
	SyncWaitResult bool
	GpuCardIndex   int32
}

type StartMergeStreamResponse struct {
	Code int32
	Msg  string
	Ssrc string
}

type GetMergeStreamStatusRequest struct {
	Ssrc string
	Tid  string
}

type GetMergeStreamStatusResponse struct {
	Code         int32
	Msg          string
	Ssrc         string
	CmdStatus    int32
	CmdStatusTip string
}

type StopMergeStreamRequest struct {
	Ssrc string
	Tid  string
}

type JobTimeAbsolute struct {
	Year        int32
	Month       int32
	Day         int32
	Hour        int32
	Minute      int32
	Second      int32
	MilliSecond int32
}
type HistorySnapshotJob struct {
	ImageName         string //图片前缀_国标ID_结构化中心ID_抽图时间戳_抽图日期时间.扩展名
	OffsetMillisecond int64
	//TODO JSON
	ServerInfos []ServerInfo `json:"ServerInfo"`

	TimePoint time.Time `json:"-"` //冗余字段，方便调试，值同OffsetMillisecond
}

type RealtimeSnapshotJob struct {
	ImageName string //图片前缀_国标ID_结构化中心ID_抽图时间戳_抽图日期时间.扩展名
	JobTime   JobTimeAbsolute
	//TODO JSON
	ServerInfos []ServerInfo `json:"ServerInfo"`

	TimePoint    time.Time                            `json:"-"` //冗余字段，计算使用，值同JobTime
	MapSubscribe map[int64][]rpcx_work_flow.Subscribe `json:"-"` //冗余字段，计算使用
}

type ServerInfo struct {
	UrlParam    string                  `json:"UrlParam"`    //人工智能服务地址
	PassInfoStr string                  `json:"PassInfoStr"` //透传字段
	PassInfo    rpcx_work_flow.PassInfo `json:"-"`           //冗余字段，计算使用
}
type AddHistorySnapshotRequest struct {
	Tid                  string
	IdRecTask            int64 `json:"IdRecTask"` //同 GroupId
	App                  string
	Stream               string
	DeviceId             string `json:"-"` //冗余字段，计算使用
	SendSnapshotToServer bool
	AllJobs              []HistorySnapshotJob
}
type AddRealtimeSnapshotRequest struct {
	Tid                  string
	IdRecTask            int64 `json:"IdRecTask"` //同 GroupId
	App                  string
	Stream               string
	DeviceId             string `json:"-"` //冗余字段，计算使用
	SendSnapshotToServer bool
	AllJobs              []RealtimeSnapshotJob
}

type SnapshotJobStatus struct {
	OffsetMillisecond int32
	ImageName         string
	JobTime           JobTimeAbsolute
	ServerInfo        []ServerInfo
}

type AddSnapshotResponse struct {
	code int32
	msg  string
}

type DelSnapshotRequest struct {
	Tid        string
	AllGroupId []RealtimeSnapshotJob
	App        string
	Stream     string
}

type QuerySnapshotStatusRequest struct {
	Tid string
	/**
	 * 如果为空,则返回url对应的最近的groupId
	 */
	GroupId   string //已更改，作废
	IdRecTask int64  //同GroupId
	/**
	 * IdRecTask和app/stream不能同时为空
	 */
	App    string
	Stream string
}

type QuerySnapshotStatusResponse struct {

	/**
	 * 200-查询成功并且有job； 204-查询成功但是没有job
	 */
	Code                 int32
	Msg                  string
	GroupId              string
	App                  string
	Stream               string
	SendSnapshotToServer bool
	IsRealtime           bool
	/**
	 * 未执行的job列表
	 */
	AllJobsStatus []SnapshotJobStatus
}

/////////////////////////////////////////////////////
//////////  go routines  /////////////////////////////
/////////////////////////////////////////////////////

func AddStreamProxy(ctx *server.Context) error {
	// get go request
	fmt.Println("start addStreamProxy")
	goRequest := AddStreamProxyParam{}
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}
	goReply := CommonResponse{}
	ctx.Write(goReply)
	return nil
}

func GetStreamStatus(ctx *server.Context) error {
	fmt.Println("start GetStreamStatus")
	// get go request
	var goRequest GetStreamStatusRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	// convert C resonse to go response
	var goReply AllStreamStatResponse
	ctx.Write(goReply)
	return nil
}

func OpenRtpServer(ctx *server.Context) error {
	fmt.Println("start OpenRtpServer")
	// get go request
	var goRequest OpenRtpServerRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	var goReply OpenRtpServerResponse
	ctx.Write(goReply)
	return nil
}

func OpenRtpServerForHistory(ctx *server.Context) error {
	fmt.Println("start OpenRtpServerForHistory")
	// get go request
	var goRequest OpenRtpServerForHistoryRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	var goReply CommonResponse
	ctx.Write(goReply)
	return nil
}

func GetM3u8Url(ctx *server.Context) error {
	fmt.Println("start GetM3u8Url")
	return errors.New("NotImplemented")
}

func StartMergeStream(ctx *server.Context) error {

	fmt.Println("start StartMergeStream")

	// get go request
	var goRequest StartMergeStreamRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	var goReply StartMergeStreamResponse

	ctx.Write(goReply)

	return nil
}

func GetMergeStreamStatus(ctx *server.Context) error {

	fmt.Println("start GetMergeStreamStatus")

	// get go request
	var goRequest GetMergeStreamStatusRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}
	// convert C resonse to go response
	var goReply GetMergeStreamStatusResponse
	ctx.Write(goReply)

	return nil
}

func StopMergeStream(ctx *server.Context) error {

	fmt.Println("start StopMergeStream")

	// get go request
	var goRequest StopMergeStreamRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	// convert C resonse to go response
	var goReply CommonResponse

	ctx.Write(goReply)

	return nil
}

func AddRealtimeSnapshot(ctx *server.Context) error {

	fmt.Println("start AddRealtimeSnapshot")

	// get go request
	var goRequest AddRealtimeSnapshotRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	// convert C resonse to go response
	var goReply CommonResponse
	ctx.Write(goReply)

	return nil
}

func AddHistorySnapshot(ctx *server.Context) error {

	fmt.Println("start AddHistorySnapshot")
	// get go request
	var goRequest AddHistorySnapshotRequest
	err := ctx.Bind(&goRequest)
	if err != nil {
		return err
	}

	// convert C resonse to go response
	var goReply CommonResponse

	ctx.Write(goReply)

	return nil
}

func DelSnapshot(ctx *server.Context) error {

	fmt.Println("start DelSnapshot")

	// // get go request
	// var goRequest DelSnapshotRequest
	// err := ctx.Bind(&goRequest)
	// if err != nil {
	// 	return err
	// }

	// // declare C var
	// var cRequest C.DelSnapshotRequest
	// var cResponse C.CommonResponse

	// // convert go request to C request
	// cRequest.tid = C.CString(goRequest.Tid)
	// cRequest.allGroupIdCount = C.int32_t(len(goRequest.allGroupId))
	// for i := 0; i < len(goRequest.allGroupId); i++ {
	// 	C.setStringByIndex(cRequest.allGroupId, C.int32_t(i), C.CString(goRequest.allGroupId[i]))
	// }
	// cRequest.app = C.CString(goRequest.App)
	// cRequest.stream = C.CString(goRequest.Stream)

	// // call C API
	// C.CallDelSnapshot(&cResponse, &cRequest)

	// // convert C resonse to go response
	// var goReply CommonResponse
	// goReply.Code = int32(cResponse.code)
	// goReply.Msg = C.GoString(cResponse.msg)
	// ctx.Write(goReply)

	// // free C response
	// C.free(unsafe.Pointer(cResponse.msg))

	return errors.New("NotImplemented")
}

func QuerySnapshot(ctx *server.Context) error {

	fmt.Println("start QuerySnapshot")

	// // get go request
	// var goRequest QuerySnapshotStatusRequest
	// err := ctx.Bind(&goRequest)
	// if err != nil {
	// 	return err
	// }

	// // declare C var
	// var cRequest C.QuerySnapshotStatusRequest
	// var cResponse C.QuerySnapshotStatusResponse

	// // convert go request to C request
	// cRequest.tid = C.CString(goRequest.Tid)
	// cRequest.groupId = C.CString(goRequest.GroupId)
	// cRequest.app = C.CString(goRequest.App)
	// cRequest.stream = C.CString(goRequest.Stream)

	// // call C API
	// C.CallQuerySnapshot(&cResponse, &cRequest)

	// // convert C resonse to go response
	// var goReply QuerySnapshotStatusResponse
	// goReply.Code = int32(cResponse.code)
	// goReply.Msg = C.GoString(cResponse.msg)
	// goReply.groupId = C.GoString(cResponse.groupId)
	// goReply.app = C.GoString(cResponse.app)
	// goReply.stream = C.GoString(cResponse.stream)
	// goReply.sendSnapshotToServer = bool(cResponse.sendSnapshotToServer)
	// goReply.isRealtime = bool(cResponse.isRealtime)
	// allJobsStatusCount := int32(cResponse.allJobsStatusCount)
	// goReply.allJobsStatus = [allJobsStatusCount]SnapshotJobStatus{}
	// for i := 0; i < allJobsStatusCount; i++ {
	// 	cJobStatusIndex := C.int32_t(i)
	// 	goReply.allJobsStatus[i].jobTime.year = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.year)
	// 	goReply.allJobsStatus[i].jobTime.month = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.month)
	// 	goReply.allJobsStatus[i].jobTime.day = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.day)
	// 	goReply.allJobsStatus[i].jobTime.hour = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.hour)
	// 	goReply.allJobsStatus[i].jobTime.minute = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.minute)
	// 	goReply.allJobsStatus[i].jobTime.second = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.second)
	// 	goReply.allJobsStatus[i].jobTime.milliSecond = int32(cResponse.allJobsStatus[cJobStatusIndex].jobTime.milliSecond)
	// 	goReply.allJobsStatus[i].offsetMillisecond = int32(cResponse.allJobsStatus[i].offsetMillisecond)
	// 	goReply.allJobsStatus[i].imageName = C.GoString(cResponse.allJobsStatus[i].imageName)

	// 	jobServerInfoCount := len(cResponse.allJobsStatus[i].jobServerInfoCount)
	// 	for j := 0; j < jobServerInfoCount; j++ {
	// 		cJobServerInfoIndex := C.int32_t(j)
	// 		goReply.allJobsStatus[i].allJobsStatus[j].serverIp = C.GoString(cResponse.allJobsStatus[i].allJobsStatus[cJobServerInfoIndex].serverIp)
	// 		goReply.allJobsStatus[i].allJobsStatus[j].serverPort = int32(cResponse.allJobsStatus[i].allJobsStatus[cJobServerInfoIndex].serverPort)
	// 		goReply.allJobsStatus[i].allJobsStatus[j].otherInfo = C.GoString(cResponse.allJobsStatus[i].allJobsStatus[cJobServerInfoIndex].otherInfo)
	// 	}
	// }

	// ctx.Write(goReply)

	// // free C response
	// C.free(unsafe.Pointer(cResponse.msg))
	// C.free(unsafe.Pointer(cResponse.groupId))
	// C.free(unsafe.Pointer(cResponse.app))
	// C.free(unsafe.Pointer(cResponse.stream))
	// C.free(unsafe.Pointer(cResponse.allJobsStatus))

	return errors.New("NotImplemented")
}

func SmokeTest(ctx *server.Context) error {
	fmt.Println("Smoke test pass in server side")
	return nil
}

//export StartListen
func StartListen() {
	println("rpcx server listening on port 8972")
	s := server.NewServer()
	s.AddHandler("MediaServer", "SmokeTest", SmokeTest)                             //烟雾测试
	s.AddHandler("MediaServer", "AddStreamProxy", AddStreamProxy)                   //添加视频流代理
	s.AddHandler("MediaServer", "GetStreamStatus", GetStreamStatus)                 //获取视频流状态
	s.AddHandler("MediaServer", "OpenRtpServer", OpenRtpServer)                     //打开rtp 服务
	s.AddHandler("MediaServer", "OpenRtpServerForHistory", OpenRtpServerForHistory) //打开rtp 服务历史
	s.AddHandler("MediaServer", "GetM3u8Url", GetM3u8Url)                           //获取M3u8 URL
	s.AddHandler("MediaServer", "StartMergeStream", StartMergeStream)               //启动视频 合流
	s.AddHandler("MediaServer", "GetMergeStreamStatus", GetMergeStreamStatus)       //获取视频合流 状态
	s.AddHandler("MediaServer", "StopMergeStream", StopMergeStream)                 //停止视频合流
	s.AddHandler("MediaServer", "AddRealtimeSnapshot", AddRealtimeSnapshot)         //添加实时快照
	s.AddHandler("MediaServer", "AddHistorySnapshot", AddHistorySnapshot)           //添加历史快照
	// s.AddHandler("MediaServer", "delSnapshot", DelSnapshot)
	// s.AddHandler("MediaServer", "querySnapshot", QuerySnapshot)
	s.Serve("tcp", "0.0.0.0:8972")
}

func main() {}
